/**************************************************************************//**
\file  battery.c

\brief This module is used for measurment battery voltage.

\author
    Atmel Corporation: http://www.atmel.com \n
    Support email: avr@atmel.com

  Copyright (c) 2008-2012, Atmel Corporation. All rights reserved.
  Licensed under Atmel's Limited License Agreement (BitCloudTM).

\internal
  History:
    29/06/07 E. Ivanov - Created
******************************************************************************/
#if APP_DISABLE_BSP != 1

/******************************************************************************
                   Includes section
******************************************************************************/
#include <bspadc.h>
#include <bspTaskManager.h>

/******************************************************************************
                   Define(s) section
******************************************************************************/
#define ADC_AMOUNT_DISPERSION				2
#define MAX_AMOUNT_COUNTER					20
#define MAX_COUNTER_2_TIMEOUT				100

/******************************************************************************
                   Types section
******************************************************************************/
// battery states
typedef enum
{
  IDLE,      // idle
  BUSY,      // opened and ready to be used
  DATA       // performs request
} adcStates_t;

// battery descriptor
typedef struct
{
  uint16_t adcData;
  BspAdcCb_t adcCallback; // callback
  uint8_t adcChannel; // adc channel number
} AdcControl_t;

/******************************************************************************
                   Global variables section
******************************************************************************/
// Monitors current state
static adcStates_t adcState = IDLE;
static AdcControl_t adcControl;
static HAL_AdcDescriptor_t adcDescriptor;

static uint16_t adcExpectation;
static uint16_t adcAmountCnt;
static uint16_t adcTimeoutCnt;

/******************************************************************************
                   Implementations section
******************************************************************************/

/**************************************************************************//**
\brief Callback about ADC request was completed.
\param[in]
  data - result of ADC.
******************************************************************************/
void adcCallback(void)
{
	adcAmountCnt++;
	adcTimeoutCnt++;  
	if ((adcControl.adcData > (adcExpectation + ADC_AMOUNT_DISPERSION)) ||
		  (adcControl.adcData < (adcExpectation - ADC_AMOUNT_DISPERSION)))
	{
		adcExpectation = adcControl.adcData;
		adcAmountCnt = 0;
	}

	if (MAX_AMOUNT_COUNTER == adcAmountCnt)
	{
		adcAmountCnt = 0;
		adcExpectation = 0;
		adcTimeoutCnt = 0;
		bspPostTask(BSP_ADC);
		return;
	}

	if (MAX_COUNTER_2_TIMEOUT == adcTimeoutCnt)
	{
		adcAmountCnt = 0;
		adcExpectation = 0;
		adcTimeoutCnt = 0;
		bspPostTask(BSP_ADC);
		return;
	}	

	adcState = BUSY;
	readBspAdc(adcControl.adcCallback, adcControl.adcChannel);
}

/**************************************************************************//**
\brief Opens the component to use.
\return
  BC_SUCCESS - the component is ready to been use. \n
  BC_FAIL - the component is already open.
******************************************************************************/
result_t openBspAdc(void)
{
	adcExpectation = 0;
	adcAmountCnt = 0;
	adcTimeoutCnt = 0;
	if (IDLE == adcState)
	{
		adcDescriptor.tty = ADC_0;
		adcDescriptor.resolution = RESOLUTION_10_BIT;
		adcDescriptor.sampleRate = ADC_4800SPS;
		adcDescriptor.voltageReference = INTERNAL_1d1V;
		adcDescriptor.bufferPointer = &(adcControl.adcData);
		adcDescriptor.selectionsAmount = 1;
		adcDescriptor.callback = adcCallback;
		adcState = BUSY;
		HAL_OpenAdc(&adcDescriptor);
		
		return BC_SUCCESS;
	}
	return BC_FAIL;
}

/**************************************************************************//**
\brief  Closes component.
\return
  BC_SUCCESS - always.
******************************************************************************/
result_t closeBspAdc(void)
{
  if (IDLE == adcState)
    return BC_FAIL;
  adcState = IDLE;
  HAL_CloseAdc(&adcDescriptor);
  return BC_SUCCESS;
}

/**************************************************************************//**
\brief  Starts ADC request on battery channel.
\param[in]
    data - sensor data.
\return
    BC_FAIL - battery component was not opened. \n
    BC_SUCCESS - other case.
******************************************************************************/
result_t readBspAdc(BspAdcCb_t cb, uint8_t channel)
{

	if (BUSY != adcState)
		return BC_FAIL;
	adcState = DATA;

	adcControl.adcChannel = channel;
	adcControl.adcCallback = cb;

	HAL_ReadAdc(&adcDescriptor, channel);
	
	return BC_SUCCESS;
}

/**************************************************************************//**
\brief BSP battery handler.
******************************************************************************/
void bspAdcHandler(void)
{
	// 1100 - 1.10 V reference voltage expressed in mV (1100 mV)
	// 1024 - steps for 10 bit ADC
	// Resulting value is a true battery voltage expressed in mV
	adcControl.adcData = (adcControl.adcData * 1100ul) / 1024ul;

	adcState = BUSY;
	adcControl.adcCallback(adcControl.adcData);
}

#endif // APP_DISABLE_BSP != 1

// eof battery.c
